##
## This file is part of the libsigrokdecode project.
##
## Copyright (C) 2012-2015 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2019 DreamSourceLab <support@dreamsourcelab.com>
## Copyright (C) 2019 Zhiyuan Wan   <dv.xw@qq.com>
## Copyright (C) 2019 Kongou Hikari <hikari@iloli.bid>
##
## Version: 
## Modified by Shiqiu Nie(369614718@qq.com)
## Date: 2017-01-11
## Descript: 
##  1. 2017-01-10 Fixed TDI/TDO data decode, when JTAG TAP run into 
##                SHIFT-IR/SHIFT-DR status,the first bit is not a valid bit.
##  2. 2017-01-11 Fixed decode when shift only one bit.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, see <http://www.gnu.org/licenses/>.
##

import sigrokdecode as srd


# 返回字符串.
def rev_ir5( stval ) :
    # reverse
    idx = 0
    tmp = stval >> 2 
    for i in range(0,5) :
        if (tmp & (0x1<<i)) != 0 :
            idx = idx | ( 0x1 << (4-i))
        else :
            pass
    return idx


def rev_dr44( stval ) :
    # reverse
    dvv = 0
    tmp = stval >> 2 
    for i in range(0,44) :
        if (tmp & (0x1<<i)) != 0 :
            dvv = dvv | ( 0x1 << (43-i))
        else :
            pass
    return dvv


def rev_dr32( stval ) :
    # reverse
    dvv = 0
    tmp = stval >> 2 
    for i in range(0,32) :
        if (tmp & (0x1<<i)) != 0 :
            dvv = dvv | ( 0x1 << (31-i))
        else :
            pass
    return dvv


def fmt_write_dr44( drvv ) :
    str = "DM,"
    tmp = drvv & 0x3
    if tmp == 0b01 :
        str += "RD:"
    elif tmp == 0b10 :
        str += "WR:"
    else :
        str += "NOP:"

    idx = (drvv >> 34) & 0x3FF
    str += "{0:#x},".format( idx )

    val = ( drvv >> 2 ) & 0xFFFFffff
    str += "{0:#x}".format(val)
    return str

def fmt_read_dr44( drvv ) :
    str = "DM,"
    tmp = drvv & 0x3
    if tmp == 0b00 :
        str += "SUCC:"
    elif tmp == 0b11 :
        str += "BUSY:"
    else :
        str += "ERRR:"

    idx = (drvv >> 34) & 0x3FF
    str += "{0:#x},".format( idx )

    val = ( drvv >> 2 ) & 0xFFFFffff
    str += "{0:#x}".format(val)
    return str

class Decoder(srd.Decoder):
    api_version = 3
    id = 'k2wire'
    name = 'k2wire'
    longname = 'k2wire debug protocol'
    desc = 'k2wire protocol debug for e906'
    license = 'gplv2+'
    inputs = ['logic']
    outputs = ['k2wire']
    tags = ['Debug/trace']
    
    channels = (
        {'id': 'sck', 'type': 209, 'name': 'SCK',  'desc': 'Test clock'},
        {'id': 'sda', 'type': 209, 'name': 'SDA',  'desc': 'Test DATA'},
    )
    
    optional_channels = ()
    
    options = (
        {'id': 'wordsize',  'desc': 'Data wordsize',  'default': 0},
    )
    
    annotations = (
        ('1', 'sof', 'Start of frame'),
        ('2', 'eof', 'End of frame'),
        
        ('8', 'tag', 'Tag'),
        ('10', 'turn', 'Turn'),
        ('5', 'value', 'Value'),
        ('8', 'parity', 'Parity'),
    )
    
    annotation_rows = (
        ('msg', 'Msg', (0,1) ),
        ('bits', 'Bits', (2,3,4,5) ),
    )

    def __init__(self):
        self.reset()

    def reset(self):
        self.fidx = 0
        self.irvv = 0x11

    def start(self):
        self.out_ann = self.register(srd.OUTPUT_ANN)

    def putx(self, data):
        self.put( self.fidx, self.samplenum, self.out_ann, [0, [data]] )

    def decode(self):
        # sadfsadfsdaf

        # Wait for a falling edge.
        (sck,sda) = self.wait({0: 'f'})
        bstt = self.samplenum
        bpre = 0
        bval = 0
        
        state = "IDLE"     # 识别到的状态机, 最后总结所有可能状态.
        stcnt = 0          # 每个状态中期望的 bits 数量.
        st_a = 0
        st_b = 0
        st_c = 0

        stpos = 0          # 当前状态中已经识别的 bits 数量.
        stval = 0          # 二进制的 bits 汇总, 先吃进的 bit 在最低位.

        while True :
            # Wait for a rising edge on TCK.
            (sck,bval) = self.wait({0: 'r'})

            if (state != "IDLE") and (state != "ERROR") :
                stval = (stval << 1) | bval
                stpos += 1

            # Wait for a falling edge.
            (sck,sda) = self.wait({0: 'f'})
            if state == "ERROR" :
                pass
            elif state == "IDLE" :
                if bval == 0 :
                    self.put( bstt, self.samplenum, self.out_ann, [2, [str(bval)]] )
            elif state == "START" :
                self.put( bstt, self.samplenum, self.out_ann, [2, [str(bval)]] )
            elif stpos <= st_a :
                self.put( bstt, self.samplenum, self.out_ann, [3, [str(bval)]] )
            elif stpos <= (st_a + st_b) :
                self.put( bstt, self.samplenum, self.out_ann, [4, [str(bval)]] )
            else :
                self.put( bstt, self.samplenum, self.out_ann, [5, [str(bval)]] )

            bpre = bstt
            bstt = self.samplenum
            

            if ( state == "IDLE" ) :
                if bval == 0 :
                    state = "START"
                    stcnt = 3
                    stpos = 0
                    stval = 0
                    self.fidx = bpre
                else :
                    pass

            elif stpos == stcnt :
                if (state == "START") :
                    
                    if stval == 0b001 :
                        # write, IR5
                        state = "WR_INST"
                        st_a = 1
                        st_b = 5
                        st_c = 2
                    elif stval == 0b011 :
                        # write, DR
                        state = "WR_DATA"
                        st_a = 1
                        st_b = 44
                        st_c = 2
                    elif stval == 0b111 :
                        # read, DR
                        if self.irvv == 0x11 :
                            state = "RD_DATA"
                            st_a = 2
                            st_b = 44
                            st_c = 2
                        else :
                            st_a = 2
                            st_b = 32
                            st_c = 2
                    else :
                        state = "ERROR"
                        st_a = 0
                        st_b = 0
                        st_c = 0

                    # total cnt.
                    stpos = 0
                    stval = 0
                    stcnt = st_a + st_b + st_c

                elif state == "WR_INST" :
                    state = "IDLE"
                    self.irvv = rev_ir5(stval)
                    self.putx( "W,IR,{0:#x}".format(self.irvv) )
                elif state == "WR_DATA" :
                    state = "IDLE"
                    if self.irvv == 0x11 :
                        drvv = rev_dr44( stval )
                        self.putx( "W,DR,{0:#x}, ".format(drvv) + fmt_write_dr44(drvv) )
                    else :
                        drvv = rev_dr32( stval )
                        self.putx( "W,DR,{0:#x}, ".format(drvv) )

                elif state == "RD_DATA" :
                    state = "IDLE"
                    if self.irvv == 0x11 :
                        drvv = rev_dr44( stval )
                        self.putx( "R,DR,{0:#x}, ".format(drvv) + fmt_read_dr44(drvv) )
                    else :
                        drvv = rev_dr32( stval )
                        self.putx( "R,DR,{0:#x}, ".format(drvv) )
                        
                elif state == "ERROR" :
                    pass







